package util.extension;

import play.Logger;
import play.Play;
import util.extension.annotation.ExtensionPoint;
import util.extension.annotation.IgnoreInvocation;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Extension功能的召唤师。
 */
public class ExtensionInvoker {

    public static final Map<Class<?>, List<ExtensionInvocation<InvocationContext>>> extensionMap = new ConcurrentHashMap<>();

    /**
     * 从上下文初始化指定的BusinessExtension.
     */
    public static void initExtensions() {
        extensionMap.clear();
        List<Class> categoryClazzList = Play.classloader.getAssignableClasses(ExtensionInvocation.class);

        for (Class<?> categoryClazz : categoryClazzList) {
            try {
                if (categoryClazz.isAnnotationPresent(ExtensionPoint.class)) {
                    ExtensionPoint extensionPoint = categoryClazz.getAnnotation(ExtensionPoint.class);
                    if (extensionPoint != null) {

                        String pointName = extensionPoint.value();
                        Logger.info("Found " + pointName + ":" + categoryClazz.getName());
                        // 得到此类别的所有子类，作为具体的执行子类
                        List<Class> invocationClazzList = Play.classloader.getAssignableClasses(categoryClazz);

                        for (Class invocationClazz : invocationClazzList) {
                            List<ExtensionInvocation<InvocationContext>> extensionInvocationList = extensionMap.computeIfAbsent(categoryClazz, k -> new ArrayList<>());
                            if (!categoryClazz.isAnnotationPresent(IgnoreInvocation.class)) {
                                // 只加入没有Ingore的类
                                ExtensionInvocation<InvocationContext> invocation = (ExtensionInvocation<InvocationContext>) invocationClazz.newInstance();
                                extensionInvocationList.add(invocation);
                            }
                        }
                    }
                    // TODO: extensionInvocationList需要排序?
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // TODO: public static List<ExtensionResult> runMatchs(...)

    public static ExtensionResult run(Class<?> extensionPointName, InvocationContext context) {
        return run(extensionPointName, context, null);
    }

    /**
     * @param extensionPointName
     * @param context
     * @param defaultAction      //TODO: 这个需要有一个专门接口，不要用BusinessExtension
     * @return
     */
    public static <T extends InvocationContext> ExtensionResult run(Class<?> extensionPointName,
                                      T context, DefaultAction<T> defaultAction) {
        List<ExtensionInvocation<InvocationContext>> extensionList = extensionMap.get(extensionPointName);

        ExtensionResult result = null;
        if (extensionList != null) { //无配置时会出现NullPointException
            for (ExtensionInvocation<InvocationContext> invocation : extensionList) {
                if (invocation.match(context)) {
                    if (invocation.processNextInvocationIfMatched()) {
                        result = invocation.execute(context);
                    } else {
                        return invocation.execute(context);
                    }
                }
            }
        }
        
        if (result != null) {
            return result; //返回最后一个result.
        }

        // TODO: 接下来考虑做一下包装模式
        if (defaultAction != null) {
            return defaultAction.execute(context);
        }
        Logger.info("LOG93719: Not Found Any %s or DefaultAction to run!",  extensionPointName.getName());
        return ExtensionResult.code(-1).message("Not Found Any Invocation");
    }

}
